# frozen_string_literal: true

# 处理安装包的各种问题，运用到 Ubuntu 系统的 apt 命令，Suse 系统的 zypper 命令等。

require 'yaml'
require_relative 'shell'
require_relative 'env'

class Packages
  def initialize(package_manager, package_manager_name)
    @package_manager = package_manager
    @package_manager_name = package_manager_name.to_sym
    @package_info = load_package_info
  end

  # install 方法支持两种模式。
  #
  # 1. 普通的包名，如 'libevent-devel'.
  # 2. 一个 Hash，它对应包处理器下的报名，如
  #
  #    { 
  #      apt: 'libevent-dev'
  #      zypper: 'libevent-devel',
  #      default: 'libevent-dev'
  #    }
  #
  # 3. 带有冒号（:）的包名，它由包管理器去解释实际的包映射，如 'libevent:devel'.
  def install(*packages)
    packages = packages.flatten.map do |package_info|
      if package_info.is_a?(Hash)
        resolve_package_from_hash(package_info)
      else # is a String
        resolve_package_from_yaml_file(package_info)
      end
    end

    @package_manager.install packages
  end

  private

    def resolve_package_from_yaml_file(package_name)
      return package_name unless @package_info.key?(package_name)

      package_info = @package_info[package_name]
      return resolve_package_from_hash(package_info)
    end

    def resolve_package_from_hash(package_info)
      package = package_info[@package_manager_name] || package_info[:default]
      if package.nil?
        raise <<~ERROR_MESSAGE
            想要根据包管理器的不同安装不同的包，但未发现当前支持的包管理器。
            安装列表：#{package_info}；
            当前包管理器：#{@package_manager_name}.
        ERROR_MESSAGE
      else
        return package
      end
    end

    def load_package_info
      package_infos = YAML.load_file(File.join(__dir__, '../package_info.yml'))
      package_infos.map do |package_name, package_info|
        raise 'package_info 必须是一个 Hash 对象' unless package_info.is_a?(Hash)

        package_info = package_info.transform_keys { |key| key.to_sym }
        package_info[:default] = package_name unless package_info.key?(:default)
        [ package_name, package_info ]
      end.to_h
    end
end

def packages
  raise '未指定包管理器' if env['package_manager']

  # 首先获取包管理器名称
  package_manager_name = env['package_manager'].downcase

  # 然后构建 package_manager
  require_relative "packages/#{package_manager_name}"
  package_manager_class_name = package_manager_name.dup
  package_manager_class_name[0] = package_manager_class_name[0].upcase
  package_manager_class = PackageManager.const_get(package_manager_class_name)
  package_manager = package_manager_class.new

  #  然后构建 the_packages
  the_packages = Packages.new(package_manager, package_manager_name)

  # 然后定义 packages 的方法
  define_method(:packages) { the_packages }

  the_packages
end
